package com.zerocarbon.framework.common.utils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.zerocarbon.framework.common.constants.CommonConstant;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.util.TextUtils;

import java.io.*;
import java.util.*;

/**
 * 服务端的restful接口帮助类
 * @author wyf
 *
 */
public class RestUtil {
	
	/**************************************MD5生成签名*******************************************/
	/**
	 * MD5验签(sort(接口参数) + app_secret) 
	 * @param appSecret
	 * @param json
	 * @return
	 */
	public static boolean validateSgin(String json, String appSecret) {
		Map<String, String> params = jsonToMap(json);
		if(StringUtils.isEmpty(appSecret))
			return false;
		return getSign(params, appSecret, CommonConstant.DEFAULT_CHARSET_UTF8).equals(params.get(CommonConstant.DEFAULT_SIGN_PARAM));
	}
	
	/**
	 * MD5验签(sort(接口参数) + app_secret) 
	 * @param params
	 * @param appSecret
	 * @return
	 */
	public static boolean validateSgin(Map<String, String> params, String appSecret) {
		if(StringUtils.isEmpty(appSecret))
			return false;
//		TODO 验签
		return getSign(params, appSecret, CommonConstant.DEFAULT_CHARSET_UTF8).equals(params.get(CommonConstant.DEFAULT_SIGN_PARAM));
	}
	
	/**
	 * MD5签名生成(sort(接口参数) + app_secret) 
	 * @param json
	 * @param appSecret
	 * @param inputCharset
	 * @return
	 */
	public static String getSign(String json, String appSecret, String inputCharset) {
		Map<String, String> params = jsonToMap(json);
		return getSign(params, appSecret, inputCharset);
	}
	
	/**
	 * 生产签名生成
	 * @param params		参数集合
	 * @param appSecret		用于加密的appSecret
	 * @param inputCharset	编码格式	如:UTF-8
	 * @return
	 */
	public static String getSign(Map<String, String> params, String appSecret, String inputCharset) {
		return sign(getParamStrForSign(params, appSecret), inputCharset).toLowerCase();
	}
	
	/**
	 * 把参数拼接成用于签名的字符串
	 * @param params
	 * @param appSecret
	 * @return
	 */
	public static String getParamStrForSign(Map<String, String> params, String appSecret) {
		StringBuffer sb = new StringBuffer();
		if(params!=null) {
			List<String> keys = new ArrayList<String>(params.keySet());
			Collections.sort(keys);
			for (int i = 0; i < keys.size(); i++) {
				String key = keys.get(i);
				String value = params.get(key);
				if (StringUtils.isNotEmpty(value) && !CommonConstant.DEFAULT_SIGN_PARAM.equals(key)) {
					if(sb.length()>0)
						sb.append("&" + key + "=" + value);
					else
						sb.append(key + "=" + value);
				}
			}
		}
		if(StringUtils.isNotEmpty(appSecret))
			sb.append(appSecret);
		return sb.toString();
	}
	
	/**
	 * MD5签名字符串
	 * @param text	需要签名的字符串
	 * @param input_charset 编码格式	如:UTF-8
	 * @return
	 */
    public static String sign(String text, String input_charset) {
    	byte[] by = null;
    	try {
    		if(input_charset == null || "".equals(input_charset)) {
    			by = text.getBytes();
            } else
            	by = text.getBytes(input_charset);
        } catch (UnsupportedEncodingException e) {
            System.out.println("MD5签名过程中出现错误,指定的编码集不对,您目前指定的编码集是:" + input_charset+ " " + e.getMessage());
        }
        return DigestUtils.md5Hex(by);
    }
    
    /**************************************文件、流的工具类*******************************************/
    /**
	 * 读取文件内容的二进制数据
	 * @param filePath
	 * @return
	 */
	public static byte[] readFile(String filePath) {
		File file = new File(filePath);
        long len = file.length();
        byte[] bytes = new byte[(int) len];
        BufferedInputStream bis = null;
		try {
			bis = new BufferedInputStream(new FileInputStream(file));
			int r = bis.read(bytes);
			if (r != len)
				throw new IOException("读取文件不正确");
			bis.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				bis.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
        return bytes;
    }
	
	/**
	 * 把文件转化成文件字节
	 * @param file
	 * @return
	 */
	public static byte[] fileToByte(File file) {
		byte[] a = null;
		FileInputStream fis = null;
		ByteArrayOutputStream bos = null;
		try {
			fis = new FileInputStream(file);
			bos = new ByteArrayOutputStream();
			byte[] buf = new byte[4096];
			int len;
			while ((len = fis.read(buf, 0, buf.length)) != -1) {
				bos.write(buf, 0, len);
			}
			//System.out.println(os.toString(Const.DEFAULT_UTF8));
			a = bos.toByteArray();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				if (fis != null)
					fis.close();
				if (bos != null)
					bos.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return a;
	}
	
	/**
	 * 把base64数据转化成二进制然后保存到本地
	 * @param base64String  base64数据
	 * @param filePath		保存文件路径
	 */
	public static void base64ToFile(String base64String, String filePath) {
		try {
			byte[] bytes = Base64.decodeBase64(base64String.getBytes());
			byteToFile(bytes, filePath);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 把文件字节以文件形式保存在本地(把字节转化成文件、把公章图片的base64数据转化成二进制，然后用该方法保存成本地图片)
	 * @param bytes	文件字节
	 * @param filePath	文件路径 格式:E:\\bbc_project_new\\app\\test.jpg
	 * @return
	 */
	public static void byteToFile(byte[] bytes, String filePath) {
		InputStream in = null;
		OutputStream out = null;
		try {
			in = new ByteArrayInputStream(bytes);
			out = new FileOutputStream(new File(filePath));  
			byte[] buf = new byte[4096];
			int r;
			while ((r = in.read(buf, 0, buf.length)) > 0) {
				out.write(buf, 0, r);
				//out.flush();
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				in.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
			try {
				out.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
	
	/**
	 * 将二进制数据写入文件内容
	 * @param data
	 * @param filePath
	 */
	public static void writeFile(byte[] data, String filePath) {
		try {
			BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(filePath));
			bufferedOutputStream.write(data);
			bufferedOutputStream.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

    /**************************************其他工具类*******************************************/
    /**
	 * 获取时间戳
	 * @return
	 */
	public static Long getTimeStamp() {
		return System.currentTimeMillis() / 1000;
	}
	
    /**
	 * 获取随机数,字母加数字组成
	 * @param length 随机数长度
	 * @return
	 */
	public static String getNonceStr(int length) {
		String chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
		String res = "";
		for (int i = 0; i < length; i++) {
			Random rd = new Random();
			int index = rd.nextInt(chars.length() - 1);
			res += chars.substring(index, index+1) ;
		}
		return res;
	}

	/**
	 * 获取长度为16的随机数,字母加数字组成
	 * @return
	 */
	public static String getNonceStr() {
		return getNonceStr(16);
	}
	
	/**
	 * 把json转化成map, 有子节点的不需要放入map中
	 * @param json
	 * @return
	 */
	public static Map<String, String> jsonToMap(String json) {
		Map<String, String> result = new HashMap<String, String>();
		if(json!=null && !"".equals(json)) {
			try {
				JSONObject jsonobject = JSON.parseObject(json);
				for(String key : jsonobject.keySet()) {
					String value = jsonobject.getString(key);
					if(isTextForJsonValue(value))
						result.put(key, value);
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return result;
	}
	
	private static boolean isTextForJsonValue(String value) { //是否有子节点
		if(TextUtils.isEmpty(value))
			return false;
	    final char[] strChar = value.substring(0, 1).toCharArray(); 
	    final char firstChar = strChar[0];
	    //System.out.println("getJSONType firstChar = "+firstChar); 
	    if(firstChar != '{' && firstChar != '[' )
	    	return true;
	    
	    return false;
	}
}
